<template>
  <div class="app-container">
    <div class="preview-container">
      <!-- 添加科技感光线效果 -->
      <div class="light-effect"></div>
      
      <!-- 添加技术线条装饰 -->
      <div class="tech-lines"></div>
      
      <!-- 添加粒子效果容器 -->
      <div class="particles-container"></div>
      
      <canvas ref="canvasRef" class="canvas"></canvas>
    </div>
    
    <div class="controls-panel">
      <h2>书籍参数设置</h2>
      
      <!-- 封面图片上传 -->
      <div class="control-group">
        <label for="coverImage">封面图片:</label>
        <input 
          type="file" 
          id="coverImage" 
          accept="image/*"
          @change="handleCoverImageUpload"
        />
        <label for="coverImage" class="file-upload-btn">
          选择图片
        </label>
        <button 
          class="clear-btn" 
          @click="clearCoverImage"
          v-if="isCustomCover"
        >
          清除
        </button>
      </div>
      
      <!-- 书籍宽度设置 -->
      <div class="control-group">
        <label for="bookWidth">书籍宽度:</label>
        <input 
          type="range" 
          id="bookWidth" 
          min="10" 
          max="40" 
          step="1" 
          v-model.number="bookParams.width"
          @input="updateBook"
        />
        <span class="value-display">{{ bookParams.width.toFixed(0) }}</span>
      </div>
      
      <!-- 书籍高度设置 -->
      <div class="control-group">
        <label for="bookHeight">书籍高度:</label>
        <input 
          type="range" 
          id="bookHeight" 
          min="15" 
          max="50" 
          step="1" 
          v-model.number="bookParams.height"
          @input="updateBook"
        />
        <span class="value-display">{{ bookParams.height.toFixed(0) }}</span>
      </div>
      
      <!-- 书籍厚度设置 -->
      <div class="control-group">
        <label for="bookThickness">书籍厚度:</label>
        <input 
          type="range" 
          id="bookThickness" 
          min="0.1" 
          max="5" 
          step="0.1" 
          v-model.number="bookParams.thickness"
          @input="updateBook"
        />
        <span class="value-display">{{ bookParams.thickness.toFixed(1) }}</span>
      </div>

      <!-- 书脊颜色设置 -->
      <div class="control-group">
        <label for="spineColor">书脊颜色:</label>
        <input 
          type="color" 
          id="spineColor" 
          v-model="bookParams.spineColor"
          @input="updateBook"
        />
      </div>

      <!-- 书脊图片上传 -->
      <div class="control-group">
        <label for="spineImage">书脊图片:</label>
        <input 
          type="file" 
          id="spineImage" 
          accept="image/*"
          @change="handleSpineImageUpload"
        />
        <label for="spineImage" class="file-upload-btn">
          选择图片
        </label>
        <button 
          class="clear-btn"
          v-if="spineTexture"
          @click="clearSpineImage"
        >
          清除图片
        </button>
      </div>

      <!-- 书籍旋转角度设置 -->
      <div class="control-group">
        <label for="rotationX">X轴旋转:</label>
        <input 
          type="range" 
          id="rotationX" 
          min="-90" 
          max="90" 
          step="1" 
          v-model.number="bookParams.rotationX"
          @input="updateBookRotation"
        />
        <span class="value-display">{{ bookParams.rotationX }}</span>
      </div>

      <div class="control-group">
        <label for="rotationY">Y轴旋转:</label>
        <input 
          type="range" 
          id="rotationY" 
          min="-180" 
          max="180" 
          step="1" 
          v-model.number="bookParams.rotationY"
          @input="updateBookRotation"
        />
        <span class="value-display">{{ bookParams.rotationY }}</span>
      </div>

      <!-- 书脊文本设置 -->
      <h3>书脊文本</h3>
      
      <div class="control-group">
        <label for="bookTitle">书名:</label>
        <input 
          type="text" 
          id="bookTitle" 
          v-model="bookParams.bookTitle"
          @input="updateBook"
          placeholder="请输入书名"
        />
      </div>

      <div class="control-group">
        <label for="authorName">笔名:</label>
        <input 
          type="text" 
          id="authorName" 
          v-model="bookParams.authorName"
          @input="updateBook"
          placeholder="请输入笔名"
        />
      </div>

      <div class="control-group">
        <label for="titleColor">书名颜色:</label>
        <input 
          type="color" 
          id="titleColor" 
          v-model="bookParams.titleColor"
          @input="updateBook"
        />
      </div>

      <div class="control-group">
        <label for="titleSize">书名大小:</label>
        <input 
          type="range" 
          id="titleSize" 
          min="12" 
          max="100" 
          step="2" 
          v-model.number="bookParams.titleSize"
          @input="updateBook"
        />
        <span class="value-display">{{ bookParams.titleSize }}</span>
      </div>

      <div class="control-group">
        <label for="titleFont">书名字体:</label>
        <select 
          id="titleFont" 
          v-model="bookParams.titleFont"
          @change="updateBook"
        >
          <option value="Microsoft YaHei">微软雅黑</option>
          <option value="SimHei">黑体</option>
          <option value="SimSun">宋体</option>
          <option value="KaiTi">楷体</option>
          <option value="FangSong">仿宋</option>
          <option value="Arial">Arial</option>
          <option value="Times New Roman">Times New Roman</option>
        </select>
      </div>

      <div class="control-group">
        <label for="authorColor">笔名颜色:</label>
        <input 
          type="color" 
          id="authorColor" 
          v-model="bookParams.authorColor"
          @input="updateBook"
        />
      </div>

      <div class="control-group">
        <label for="authorSize">笔名大小:</label>
        <input 
          type="range" 
          id="authorSize" 
          min="10" 
          max="80" 
          step="2" 
          v-model.number="bookParams.authorSize"
          @input="updateBook"
        />
        <span class="value-display">{{ bookParams.authorSize }}</span>
      </div>

      <div class="control-group">
        <label for="authorFont">笔名字体:</label>
        <select 
          id="authorFont" 
          v-model="bookParams.authorFont"
          @change="updateBook"
        >
          <option value="Microsoft YaHei">微软雅黑</option>
          <option value="SimHei">黑体</option>
          <option value="SimSun">宋体</option>
          <option value="KaiTi">楷体</option>
          <option value="FangSong">仿宋</option>
          <option value="Arial">Arial</option>
          <option value="Times New Roman">Times New Roman</option>
        </select>
      </div>

      <!-- 场景设置 -->
      <h3>场景设置</h3>
      
      <div class="control-group">
        <label for="backgroundColor">背景颜色:</label>
        <input 
          type="color" 
          id="backgroundColor" 
          v-model="sceneParams.backgroundColor"
          @input="updateBackground"
          :disabled="sceneParams.transparentBackground || !!sceneParams.backgroundImage"
        />
      </div>

      <!-- 背景图片上传 -->
      <div class="control-group">
        <label for="backgroundImage">背景图片:</label>
        <input 
          type="file" 
          id="backgroundImage" 
          accept="image/*"
          @change="handleBackgroundImageUpload"
        />
        <label for="backgroundImage" class="file-upload-btn">
          选择图片
        </label>
        <button 
          class="clear-btn"
          v-if="sceneParams.backgroundImage"
          @click="clearBackgroundImage"
        >
          清除图片
        </button>
      </div>

      <div class="control-group">
        <label class="checkbox-label">
          <input 
            type="checkbox" 
            v-model="sceneParams.transparentBackground"
            @change="updateBackground"
          />
          透明背景
        </label>
      </div>

      <div class="control-group">
        <label for="resolutionScale">导出分辨率:</label>
        <select 
          id="resolutionScale" 
          v-model.number="sceneParams.resolutionScale"
        >
          <option value="1">原始 (1x)</option>
          <option value="2">高清 (2x)</option>
          <option value="3">超清 (3x)</option>
        </select>
      </div>

      <!-- 下载按钮 -->
      <button 
        class="download-btn" 
        @click="downloadBookImage"
        :disabled="!isCanvasReady"
      >
        下载3D效果图
      </button>

      <!-- 重置按钮 -->
      <button 
        class="reset-btn" 
        @click="resetParameters"
      >
        重置所有参数
      </button>
    </div>
    
    <!-- 版权信息 - 缩放卡片 -->
    <div class="copyright-container">
      <button 
        class="copyright-toggle"
        @click="toggleCopyright"
        title="显示/隐藏版权信息"
      >
        <span class="toggle-icon">©</span>
        <span class="toggle-text" v-if="showCopyright">收起</span>
        <span class="toggle-text" v-else>关于</span>
      </button>
      
      <div class="copyright-info" :class="{ 'expanded': showCopyright }">
        <p>关于软件：这是一个基于Vue.js和Three.js的3D封面生成器，用户可以自定义书名、笔名、背景颜色、背景图片等参数，生成个性化的3D封面效果。</p>
        <p>微信公众号：sharecho</p>
        <p>企鹅号：1346363063</p>
        <p>QQ群：1051808307</p>
        <p>技术支持：160540168(QQ)</p>
        <p>Gitee项目：<a href="https://gitee.com/WitOpenSource/wit-create-your-3dcover-app" target="_blank" rel="noopener noreferrer">WitCreateYour3DCoverAPP</a></p>
        <p>© 2025 云墨北</p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { ParticleEffect, TechLinesEffect } from './utils/particleEffect.js'

// Refs
const canvasRef = ref<HTMLCanvasElement>()
const isCanvasReady = ref(false)
const showCopyright = ref(false) // 控制版权信息显示状态

// 切换版权信息显示/隐藏
function toggleCopyright() {
  showCopyright.value = !showCopyright.value
}

// 粒子效果和技术线条效果实例
let particleEffect: ParticleEffect | null = null
let techLinesEffect: TechLinesEffect | null = null

// 书籍参数
const bookParams = ref({
  width: 20.0,
  height: 28.0,
  thickness: 3.5,
  spineColor: '#000000',
  rotationX: 20,
  rotationY: 45,
  bookTitle: '我的书名',
  authorName: '我的笔名',
  titleColor: '#ffffff',
  titleSize: 36,
  titleFont: 'Microsoft YaHei',
  authorColor: '#ffffff',
  authorSize: 24,
  authorFont: 'Microsoft YaHei'
})

// 场景参数
const sceneParams = ref({
  backgroundColor: '#282828',
  backgroundImage: null as string | null,
  transparentBackground: true,
  resolutionScale: 3 // 默认分辨率缩放倍数 (1=原始, 2=2倍, 3=3倍)
})

// 封面图片相关状态
const isCustomCover = ref(false)
const customCoverUrl = ref<string | null>(null)

// Three.js 对象
let scene: THREE.Scene
let camera: THREE.PerspectiveCamera
let renderer: THREE.WebGLRenderer
let controls: OrbitControls
let book: THREE.Group
let frontTexture: THREE.Texture
let backTexture: THREE.Texture
let spineTexture: THREE.Texture | null = null
let backgroundTexture: THREE.Texture | null = null
let bookWidth = bookParams.value.width
let bookHeight = bookParams.value.height
let bookThickness = bookParams.value.thickness

// 加载封面图片并创建3D场景
  onMounted(() => {
    initThreeJs()
    loadBookTextures()
    
    // 初始化粒子效果和技术线条效果
    setTimeout(() => {
      initParticleEffects()
    }, 500)
  })

  // 检测是否在APP环境中
  function isAppEnvironment() {
    return typeof window !== 'undefined' && (window.uni !== undefined || window.plus !== undefined)
  }

onUnmounted(() => {
  // 清理资源
  if (renderer) {
    renderer.dispose()
  }
  if (frontTexture) {
    frontTexture.dispose()
  }
  if (backTexture) {
    backTexture.dispose()
  }
  if (spineTexture) {
    spineTexture.dispose()
  }
  if (backgroundTexture) {
    backgroundTexture.dispose()
  }
  
  // 销毁粒子效果和技术线条效果 - 增加更严格的安全检查
  try {
    if (particleEffect && typeof (particleEffect as { destroy: Function }).destroy === 'function') {
      particleEffect.destroy()
      particleEffect = null
    }
    if (techLinesEffect && typeof techLinesEffect.destroy === 'function') {
      techLinesEffect.destroy()
      techLinesEffect = null
    }
  } catch (error) {
    console.error('Error destroying effects:', error)
  }
})

// 初始化粒子效果和技术线条效果
function initParticleEffects() {
  // 创建粒子效果
  const particlesContainer = document.querySelector('.particles-container')
  if (particlesContainer) {
    particlesContainer.id = 'particles-container'
    if (typeof ParticleEffect === 'function') {
      particleEffect = new ParticleEffect('particles-container')
      if (typeof particleEffect.init === 'function') {
        particleEffect.init()
      }
    }
  }
  
  // 创建技术线条效果
  const techLinesContainer = document.querySelector('.tech-lines')
  if (techLinesContainer) {
    techLinesContainer.id = 'tech-lines'
    if (typeof TechLinesEffect === 'function') {
      techLinesEffect = new TechLinesEffect('tech-lines')
      if (typeof techLinesEffect.init === 'function') {
        techLinesEffect.init()
      }
    }
  }
}

// 初始化Three.js场景
function initThreeJs() {
  if (!canvasRef.value) return

  // 创建场景
  scene = new THREE.Scene()
  scene.background = sceneParams.value.transparentBackground ? null : new THREE.Color(sceneParams.value.backgroundColor)

  // 创建相机
  camera = new THREE.PerspectiveCamera(
    75,
    canvasRef.value.clientWidth / canvasRef.value.clientHeight,
    0.1,
    1000
  )
  camera.position.z = 50

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({
    canvas: canvasRef.value,
    antialias: true,
    alpha: true,  // 启用透明背景支持
    preserveDrawingBuffer: true
  })
  renderer.setSize(canvasRef.value.clientWidth, canvasRef.value.clientHeight)
  renderer.setPixelRatio(window.devicePixelRatio)
  
  // 设置渲染器参数以获得更好的视觉效果
  renderer.shadowMap.enabled = true
  renderer.shadowMap.type = THREE.PCFSoftShadowMap
  renderer.toneMapping = THREE.NoToneMapping // 不使用色调映射，避免任何可能的透明度影响
  renderer.toneMappingExposure = 1.0

  // 添加轨道控制器
  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.dampingFactor = 0.25
  controls.enableZoom = true
  controls.autoRotate = false

  // 添加光源
  const ambientLight = new THREE.AmbientLight(0xffffff, 1.0) // 增加环境光强度
  scene.add(ambientLight)

  const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5) // 增加主光源强度
  directionalLight.position.set(30, 40, 50)
  directionalLight.castShadow = true
  directionalLight.shadow.mapSize.width = 2048
  directionalLight.shadow.mapSize.height = 2048
  directionalLight.shadow.camera.near = 0.5
  directionalLight.shadow.camera.far = 200
  scene.add(directionalLight)

  // 添加补光灯
  const fillLight = new THREE.DirectionalLight(0xffffff, 0.8) // 增加补光强度
  fillLight.position.set(-30, 20, -20)
  scene.add(fillLight)

  // 添加顶部光源
  const topLight = new THREE.DirectionalLight(0xffffff, 0.6)
  topLight.position.set(0, 50, 0)
  scene.add(topLight)

  // 处理窗口大小变化
  window.addEventListener('resize', handleResize)

  // 开始渲染循环
  animate()
}

// 加载书籍纹理
function loadBookTextures() {
  // 使用自定义封面或默认封面
  // 在APP环境中使用相对路径，在Web环境中使用绝对路径
  let coverImageUrl = customCoverUrl.value
  
  // 如果没有自定义封面，使用默认封面
  if (!coverImageUrl) {
    if (isAppEnvironment()) {
      // 在APP环境中，使用相对路径
      coverImageUrl = './assets/yunmobei_demo2.png'
    } else {
      // 在Web环境中，使用绝对路径
      coverImageUrl = './assets/yunmobei_demo2.png'
    }
  }
  
  const loader = new THREE.TextureLoader()
  
  loader.load(
    coverImageUrl,
    (texture) => {
      // 设置纹理参数以获得更好的显示效果
      texture.minFilter = THREE.LinearMipmapLinearFilter
      texture.magFilter = THREE.LinearFilter
      texture.wrapS = THREE.ClampToEdgeWrapping
      texture.wrapT = THREE.ClampToEdgeWrapping
      texture.flipY = true
      
      // 释放旧纹理资源
      if (frontTexture) {
        frontTexture.dispose()
      }
      if (backTexture) {
        backTexture.dispose()
      }
      
      // 正面和背面使用同一张纹理，确保图片正确显示
      frontTexture = texture
      backTexture = texture.clone()
      backTexture.needsUpdate = true
      
      createBook()
      isCanvasReady.value = true
    },
    undefined,
    (error) => {
      console.error('Error loading cover image:', error)
    }
  )
}

// 处理封面图片上传
function handleCoverImageUpload(event: Event) {
  const target = event.target as HTMLInputElement
  if (!target.files || target.files.length === 0) return

  const file = target.files[0]
  const reader = new FileReader()

  reader.onload = (e) => {
    const dataUrl = e.target?.result as string
    customCoverUrl.value = dataUrl
    isCustomCover.value = true
    loadBookTextures()
  }

  reader.readAsDataURL(file)
}

// 清除封面图片，恢复默认封面
function clearCoverImage() {
  customCoverUrl.value = null
  isCustomCover.value = false
  const input = document.getElementById('coverImage') as HTMLInputElement
  if (input) {
    input.value = ''
  }
  loadBookTextures()
}

// 创建书籍模型 - 使用更简洁、更基础的方法构建模型，避免透明问题
function createBook() {
  if (!frontTexture || !backTexture) return

  // 移除旧的书籍模型
  if (book) {
    scene.remove(book)
    // 清理旧模型的几何体和材质
    book.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        child.geometry.dispose()
        if (Array.isArray(child.material)) {
          child.material.forEach(material => material.dispose())
        } else {
          child.material.dispose()
        }
      }
    })
  }

  book = new THREE.Group()
  
  // 计算书籍尺寸
  const width = bookWidth  // 书的宽度（从书脊到书的边缘）
  const height = bookHeight  // 书的高度
  const depth = bookThickness  // 书的厚度
  
  // 添加封面厚度
  const coverThickness = 0.1  // 封面厚度值，可以根据需要调整
  
  // 添加书籍主体缩放系数，使书模比封面缩小一些
  const bookBodyScale = 0.98  // 书籍主体缩放系数，小于1表示比封面小
  const bodyWidth = width * bookBodyScale
  const bodyHeight = height * bookBodyScale
  const bodyDepth = depth * bookBodyScale
  
  // 创建基础材质 - 使用MeshBasicMaterial避免光照和物理效果影响
  const frontMaterial = new THREE.MeshBasicMaterial({
    map: frontTexture,
    side: THREE.DoubleSide,
    transparent: false,
    opacity: 1.0
  })
  
  const backMaterial = new THREE.MeshBasicMaterial({
    map: backTexture,
    side: THREE.DoubleSide,
    transparent: false,
    opacity: 1.0
  })
  
  // 生成书脊纹理
  spineTexture = generateSpineTexture()
  
  const spineMaterial = spineTexture 
    ? new THREE.MeshBasicMaterial({
        map: spineTexture,
        side: THREE.DoubleSide, // 修改为双面渲染
        transparent: false,
        opacity: 1.0
      })
    : new THREE.MeshBasicMaterial({
        color: bookParams.value.spineColor,
        side: THREE.DoubleSide, // 修改为双面渲染
        transparent: false,
        opacity: 1.0
      })
  
  const pagesMaterial = new THREE.MeshBasicMaterial({
    color: 0xffffff,
    side: THREE.DoubleSide, // 修改为双面渲染
    transparent: false,
    opacity: 1.0
  })
  
  const topBottomMaterial = new THREE.MeshBasicMaterial({
    color: 0xf0f0f0,
    side: THREE.DoubleSide, // 修改为双面渲染
    transparent: false,
    opacity: 1.0
  })
  
  // 创建书籍主体 - 使用更简洁的方式构建各面
  
  // 1. 创建封面（前面）- 修改为有厚度的立方体
  const frontGeometry = new THREE.BoxGeometry(width, height, coverThickness)
  const frontMesh = new THREE.Mesh(frontGeometry, frontMaterial)
  frontMesh.position.set(0, 0, depth / 2 + coverThickness / 2)  // 调整位置，考虑封面厚度
  frontMesh.receiveShadow = true
  frontMesh.castShadow = true
  book.add(frontMesh)
  
  // 2. 创建封底（后面）- 修改为有厚度的立方体
  const backGeometry = new THREE.BoxGeometry(width, height, coverThickness)
  const backMesh = new THREE.Mesh(backGeometry, backMaterial)
  backMesh.position.set(0, 0, -depth / 2 - coverThickness / 2)  // 调整位置，考虑封底厚度
  backMesh.rotation.y = Math.PI
  backMesh.receiveShadow = true
  backMesh.castShadow = true
  book.add(backMesh)
  
  // 3. 创建书脊（左侧面）- 添加0.1的厚度
  const spineGeometry = new THREE.BoxGeometry(coverThickness, height, depth)
  const spineMesh = new THREE.Mesh(spineGeometry, spineMaterial)
  spineMesh.position.set(-width / 2 + coverThickness / 2, 0, 0)  // 调整位置，考虑书脊厚度
  spineMesh.receiveShadow = true
  spineMesh.castShadow = true
  book.add(spineMesh)
  
  // 4. 创建书页边缘（右侧面）
  const pagesGeometry = new THREE.PlaneGeometry(bodyDepth, bodyHeight)
  const pagesMesh = new THREE.Mesh(pagesGeometry, pagesMaterial)
  pagesMesh.position.set(bodyWidth / 2, 0, 0)
  pagesMesh.rotation.y = -Math.PI / 2
  pagesMesh.receiveShadow = true
  pagesMesh.castShadow = true
  book.add(pagesMesh)
  
  // 5. 创建书的顶部
  const topGeometry = new THREE.PlaneGeometry(bodyWidth, bodyDepth)
  const topMesh = new THREE.Mesh(topGeometry, topBottomMaterial)
  topMesh.position.set(0, bodyHeight / 2, 0)
  topMesh.rotation.x = Math.PI / 2
  topMesh.receiveShadow = true
  topMesh.castShadow = true
  book.add(topMesh)
  
  // 6. 创建书的底部
  const bottomGeometry = new THREE.PlaneGeometry(bodyWidth, bodyDepth)
  const bottomMesh = new THREE.Mesh(bottomGeometry, topBottomMaterial)
  bottomMesh.position.set(0, -bodyHeight / 2, 0)
  bottomMesh.rotation.x = -Math.PI / 2
  bottomMesh.receiveShadow = true
  bottomMesh.castShadow = true
  book.add(bottomMesh)
  
  // 设置书籍旋转
  updateBookRotation()

  // 添加书籍到场景
  scene.add(book)
}

// 更新书籍尺寸和材质
function updateBook() {
  // 保存当前书籍的旋转状态和相机位置
  let savedRotationX = 0
  let savedRotationY = 0
  let savedCameraPosition = { x: 0, y: 0, z: 0 }
  
  if (book) {
    savedRotationX = book.rotation.x
    savedRotationY = book.rotation.y
  }
  
  if (camera) {
    savedCameraPosition.x = camera.position.x
    savedCameraPosition.y = camera.position.y
    savedCameraPosition.z = camera.position.z
  }
  
  bookWidth = bookParams.value.width
  bookHeight = bookParams.value.height
  bookThickness = bookParams.value.thickness
  createBook()
  
  // 恢复保存的旋转状态和相机位置
  if (book) {
    book.rotation.x = savedRotationX
    book.rotation.y = savedRotationY
  }
  
  if (camera) {
    camera.position.set(savedCameraPosition.x, savedCameraPosition.y, savedCameraPosition.z)
    camera.updateProjectionMatrix()
  }
}

// 更新书籍旋转角度
function updateBookRotation() {
  if (book) {
    book.rotation.x = (bookParams.value.rotationX * Math.PI) / 180
    book.rotation.y = (bookParams.value.rotationY * Math.PI) / 180
  }
}

// 更新背景
function updateBackground() {
  if (sceneParams.value.transparentBackground) {
    scene.background = null
  } else if (sceneParams.value.backgroundImage && backgroundTexture) {
    scene.background = backgroundTexture
  } else {
    scene.background = new THREE.Color(sceneParams.value.backgroundColor)
  }
}

// 重置所有参数
function resetParameters() {
  // 重置书籍参数
  bookParams.value = {
    width: 20.0,
    height: 28.0,
    thickness: 3.5,
    spineColor: '#000000',
    rotationX: 20,
    rotationY: 45,
    bookTitle: '我的书名',
    authorName: '我的笔名',
    titleColor: '#ffffff',
    titleSize: 36,
    titleFont: 'Microsoft YaHei',
    authorColor: '#ffffff',
    authorSize: 24,
    authorFont: 'Microsoft YaHei'
  }

  // 重置场景参数
  sceneParams.value = {
    backgroundColor: '#282828',
    backgroundImage: null,
    transparentBackground: false,
    resolutionScale: 3
  }

  // 重置封面图片相关状态
  customCoverUrl.value = null
  isCustomCover.value = false
  const coverInput = document.getElementById('coverImage') as HTMLInputElement
  if (coverInput) {
    coverInput.value = ''
  }

  // 重置背景图片输入
  const bgInput = document.getElementById('backgroundImage') as HTMLInputElement
  if (bgInput) {
    bgInput.value = ''
  }

  // 释放背景纹理资源
  if (backgroundTexture) {
    backgroundTexture.dispose()
    backgroundTexture = null
  }

  // 重新加载封面纹理并更新书籍
  loadBookTextures()
  updateBook()
  updateBackground()
}

// 生成书脊纹理，包含竖向排版的书名和笔名
function generateSpineTexture() {
  // 释放旧的书脊纹理资源
  if (spineTexture) {
    spineTexture.dispose()
  }

  // 创建Canvas元素用于绘制
  const canvas = document.createElement('canvas')
  
  // 确定Canvas尺寸，基于书脊的高度和厚度，保持合适的比例
  // 使用动态尺寸而不是固定值，确保文字不会变形
  const bookSpineHeight = bookHeight
  const bookSpineThickness = bookThickness
  
  // 确定分辨率比例，确保清晰度
  const resolution = 30 // 每单位长度的像素数
  const canvasWidth = Math.max(64, Math.floor(bookSpineThickness * resolution))
  const canvasHeight = Math.max(256, Math.floor(bookSpineHeight * resolution))
  
  // 确保最小尺寸，防止分辨率过低
  canvas.width = canvasWidth
  canvas.height = canvasHeight

  const ctx = canvas.getContext('2d')
  if (!ctx) return null

  // 清空画布并设置背景色
  ctx.fillStyle = bookParams.value.spineColor
  ctx.fillRect(0, 0, canvasWidth, canvasHeight)

  // 如果没有设置书名，则使用纯色背景
  if (!bookParams.value.bookTitle && !bookParams.value.authorName) {
    const texture = new THREE.CanvasTexture(canvas)
    texture.needsUpdate = true
    texture.minFilter = THREE.LinearFilter
    texture.magFilter = THREE.LinearFilter
    return texture
  }

  // 设置文字基础样式
  ctx.textAlign = 'center'
  ctx.textBaseline = 'middle'

  // 创建一个组，用于放置所有文本
  const textGroup = []
  
  // 直接使用用户设置的文字大小，仅限制最大值
  // 移除基于书脊厚度的限制，确保用户调节能够立即看到效果
  const adjustedTitleSize = Math.min(bookParams.value.titleSize, 100) // 仅设置最大限制
  const adjustedAuthorSize = Math.min(bookParams.value.authorSize, 80) // 仅设置最大限制
  
  // 添加书名
  if (bookParams.value.bookTitle) {
    const title = bookParams.value.bookTitle
    // 将书名拆分为单个字符，以便竖向排版
    for (let i = 0; i < title.length; i++) {
      textGroup.push({
        text: title[i],
        size: adjustedTitleSize,
        isTitle: true,
        color: bookParams.value.titleColor,
        font: bookParams.value.titleFont
      })
    }
  }

  // 如果有书名和笔名，添加一个空格分隔
  if (bookParams.value.bookTitle && bookParams.value.authorName) {
    textGroup.push({
      text: ' ',
      size: adjustedAuthorSize,
      isTitle: false,
      color: bookParams.value.authorColor,
      font: bookParams.value.authorFont
    })
  }

  // 添加笔名
  if (bookParams.value.authorName) {
    const author = bookParams.value.authorName
    // 将笔名拆分为单个字符，以便竖向排版
    for (let i = 0; i < author.length; i++) {
      textGroup.push({
          text: author[i],
          size: adjustedAuthorSize,
          isTitle: false,
          color: bookParams.value.authorColor,
          font: bookParams.value.authorFont
        })
    }
  }

  // 计算文本总高度和起始位置
  const totalTextHeight = textGroup.reduce((sum, item) => sum + item.size * 1.5, 0)
  const startY = (canvasHeight - totalTextHeight) / 2

  // 绘制竖向文本
  let currentY = startY
  for (const item of textGroup) {
    // 设置当前文本的颜色和字体
    ctx.fillStyle = item.color
    ctx.font = `bold ${item.size}px '${item.font}', sans-serif`
    ctx.fillText(item.text, canvasWidth / 2, currentY + item.size / 2)
    currentY += item.size * 1.5
  }

  // 创建Three.js纹理，并设置正确的纹理映射属性
  const texture = new THREE.CanvasTexture(canvas)
  texture.needsUpdate = true
  texture.minFilter = THREE.LinearFilter
  texture.magFilter = THREE.LinearFilter
  // 设置纹理映射模式，防止拉伸变形
  texture.wrapS = THREE.ClampToEdgeWrapping
  texture.wrapT = THREE.ClampToEdgeWrapping

  return texture
}

// 处理书脊图片上传
function handleSpineImageUpload(event: Event) {
  const target = event.target as HTMLInputElement
  if (!target.files || target.files.length === 0) return

  const file = target.files[0]
  const reader = new FileReader()

  reader.onload = (e) => {
    const texture = new THREE.TextureLoader().load(e.target?.result as string)
    // 设置纹理参数以获得更好的显示效果
    texture.minFilter = THREE.LinearMipmapLinearFilter
    texture.magFilter = THREE.LinearFilter
    texture.wrapS = THREE.ClampToEdgeWrapping
    texture.wrapT = THREE.ClampToEdgeWrapping
    
    if (spineTexture) {
      spineTexture.dispose()
    }
    spineTexture = texture
    createBook()
  }

  reader.readAsDataURL(file)
}

// 清除书脊图片
function clearSpineImage() {
  if (spineTexture) {
    spineTexture.dispose()
    spineTexture = null
    const input = document.getElementById('spineImage') as HTMLInputElement
    if (input) {
      input.value = ''
    }
    createBook()
  }
}

// 处理背景图片上传
function handleBackgroundImageUpload(event: Event) {
  const target = event.target as HTMLInputElement
  if (!target.files || target.files.length === 0) return

  const file = target.files[0]
  const reader = new FileReader()

  reader.onload = (e) => {
    const texture = new THREE.TextureLoader().load(e.target?.result as string)
    // 设置背景纹理参数
    texture.minFilter = THREE.LinearMipmapLinearFilter
    texture.magFilter = THREE.LinearFilter
    
    if (backgroundTexture) {
      backgroundTexture.dispose()
    }
    backgroundTexture = texture
    sceneParams.value.backgroundImage = e.target?.result as string
    updateBackground()
  }

  reader.readAsDataURL(file)
}

// 清除背景图片
function clearBackgroundImage() {
  if (backgroundTexture) {
    backgroundTexture.dispose()
    backgroundTexture = null
    sceneParams.value.backgroundImage = null
    const input = document.getElementById('backgroundImage') as HTMLInputElement
    if (input) {
      input.value = ''
    }
    updateBackground()
  }
}

// 导入HBuilder专用工具
import { isHBuilderApp, saveImageToAlbumInHBuilder } from './utils/hbuilder-utils'

// 下载3D效果图 - 适配Web和HBuilder环境
function downloadBookImage() {
  if (!renderer || !canvasRef.value || !camera) return

  try {
    // 创建一个临时的高分辨率渲染器
    const tempRenderer = new THREE.WebGLRenderer({
      antialias: true,
      alpha: true,
      preserveDrawingBuffer: true
    })
    
    // 使用用户选择的分辨率
    const resolutionScale = sceneParams.value.resolutionScale
    const width = canvasRef.value.clientWidth * resolutionScale
    const height = canvasRef.value.clientHeight * resolutionScale
    
    tempRenderer.setSize(width, height)
    tempRenderer.setPixelRatio(1) // 禁用自动像素比缩放
    
    // 配置临时渲染器
    tempRenderer.shadowMap.enabled = true
    tempRenderer.shadowMap.type = THREE.PCFSoftShadowMap
    
    // 创建临时相机
    const tempCamera = camera.clone()
    tempCamera.aspect = width / height
    tempCamera.updateProjectionMatrix()
    
    // 渲染到临时渲染器
    tempRenderer.render(scene, tempCamera)
    
    // 导出高分辨率图片
    const dataURL = tempRenderer.domElement.toDataURL('image/png', 1.0) // 1.0是图像质量
    
    // 清理临时资源
    tempRenderer.dispose()
    
    // 检测是否在HBuilder环境中
    if (isHBuilderApp()) {
      // HBuilder环境：使用专用工具函数保存图片
      const fileName = `3D-book-cover-${resolutionScale}x.png`
      saveImageToAlbumInHBuilder(dataURL, fileName).catch((error) => {
        console.error('HBuilder保存图片失败:', error)
        // 最后的备用错误提示
        if (typeof window !== 'undefined' && window.uni) {
          try {
            window.uni.hideLoading()
          } catch (e) {}
          window.uni.showToast({
            title: '保存图片失败，请重试',
            icon: 'none'
          })
        }
      })
    } else {
      // Web环境：使用传统方式下载
      const link = document.createElement('a')
      link.href = dataURL
      link.download = `3D-book-cover-${resolutionScale}x.png`
      // 兼容移动Web
      if (link.click) {
        link.click()
      } else {
        // 对于不支持click()的环境
        const evt = document.createEvent('MouseEvents')
        evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
        link.dispatchEvent(evt)
      }
    }
    
  } catch (error: any) {
    console.error('下载图片时出错:', error)
    
    // 备用方案：直接使用当前渲染器导出
    try {
      const resolutionScale = sceneParams.value.resolutionScale
      const dataURL = renderer.domElement.toDataURL('image/png', 1.0)
      
      // 检测是否在HBuilder环境中
      if (isHBuilderApp()) {
        const fileName = `3D-book-cover-${resolutionScale}x.png`
        saveImageToAlbumInHBuilder(dataURL, fileName).catch((fallbackError) => {
          console.error('备用下载方案也失败:', fallbackError)
          // 最后的备用错误提示
          if (typeof window !== 'undefined' && window.uni) {
            try {
              window.uni.hideLoading()
            } catch (e) {}
            window.uni.showToast({
              title: '保存图片失败，请重试',
              icon: 'none'
            })
          }
        })
      } else {
        const link = document.createElement('a')
        link.href = dataURL
        link.download = `3D-book-cover-${resolutionScale}x.png`
        link.click()
      }
    } catch (fallbackError: any) {
      console.error('备用下载方案也失败:', fallbackError)
      
      // 显示用户友好的错误提示
      if (typeof window !== 'undefined' && window.uni) {
        try {
          window.uni.hideLoading()
        } catch (e) {}
        window.uni.showToast({
          title: '保存图片失败，请重试',
          icon: 'none'
        })
      } else if (typeof alert === 'function') {
        alert('保存图片失败，请重试')
      }
    }
  }
}

// 注意：HBuilder环境下的图片保存功能已迁移到专用工具文件中
// 请查看 src/utils/hbuilder-utils.ts 文件了解具体实现

// 处理窗口大小变化
function handleResize() {
  if (!canvasRef.value || !camera || !renderer) return

  camera.aspect = canvasRef.value.clientWidth / canvasRef.value.clientHeight
  camera.updateProjectionMatrix()
  renderer.setSize(canvasRef.value.clientWidth, canvasRef.value.clientHeight)
}

// 渲染循环
function animate() {
  requestAnimationFrame(animate)
  controls.update()
  renderer.render(scene, camera)
}
</script>

<style scoped>
.app-container {
  display: flex;
  height: 100vh;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
  color: #e0e0e0;
}

.preview-container {
  flex: 1;
  position: relative;
  background: linear-gradient(135deg, #0a192f 0%, #172a45 100%);
  overflow: hidden;
}

/* 预览容器添加科技感网格背景 */
.preview-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-image: 
    linear-gradient(rgba(95, 217, 255, 0.1) 1px, transparent 1px),
    linear-gradient(90deg, rgba(95, 217, 255, 0.1) 1px, transparent 1px);
  background-size: 30px 30px;
  pointer-events: none;
  z-index: 1;
}

/* 科技感光线效果 */
.light-effect {
  position: absolute;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  background: radial-gradient(circle, rgba(0, 188, 212, 0.1) 0%, transparent 70%);
  z-index: 2;
  pointer-events: none;
  animation: pulse 5s infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 0.3; }
  50% { opacity: 0.1; }
}

.canvas {
  width: 100%;
  height: 100%;
  display: block;
  position: relative;
  z-index: 3;
}

.download-btn {
  width: 100%;
  padding: 14px 20px;
  background: linear-gradient(135deg, #00bcd4, #2196f3);
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
  margin-top: 20px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  box-shadow: 0 4px 15px rgba(0, 188, 212, 0.3);
}

.download-btn:hover:not(:disabled) {
  background: linear-gradient(135deg, #00acc1, #1976d2);
  box-shadow: 0 6px 20px rgba(0, 188, 212, 0.4);
  transform: translateY(-2px);
}

.download-btn:disabled {
  background: linear-gradient(135deg, #616161, #757575);
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

.controls-panel {
  width: 350px;
  background: rgba(17, 25, 40, 0.95);
  backdrop-filter: blur(10px);
  padding: 24px;
  overflow-y: auto;
  box-shadow: -2px 0 20px rgba(0, 188, 212, 0.15);
  border-left: 1px solid rgba(0, 188, 212, 0.2);
}

/* 标题样式 - 科技感 */
.controls-panel h2 {
  margin-top: 0;
  margin-bottom: 24px;
  color: #00bcd4;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  position: relative;
  padding-bottom: 12px;
}

.controls-panel h2::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  width: 60px;
  height: 2px;
  background: linear-gradient(90deg, #00bcd4, #2196f3);
}

.controls-panel h3 {
  color: #95e6ff;
  font-size: 16px;
  margin: 20px 0 16px 0;
  font-weight: 600;
  letter-spacing: 0.5px;
}

.control-group {
  margin-bottom: 20px;
  position: relative;
}

.control-group label {
  display: block;
  margin-bottom: 8px;
  color: #e0e0e0;
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.5px;
}

.control-group .checkbox-label {
  display: flex;
  align-items: center;
  cursor: pointer;
  margin-bottom: 0;
}

.control-group .checkbox-label input[type="checkbox"] {
  width: auto;
  margin-right: 8px;
  cursor: pointer;
  accent-color: #00bcd4;
}

/* 滑块样式 - 科技感 */
.control-group input[type="range"] {
  width: 100%;
  margin-bottom: 4px;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.1);
}

.control-group input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: linear-gradient(135deg, #00bcd4, #2196f3);
  cursor: pointer;
  box-shadow: 0 0 10px rgba(0, 188, 212, 0.5);
  transition: all 0.2s ease;
}

.control-group input[type="range"]::-webkit-slider-thumb:hover {
  transform: scale(1.2);
  box-shadow: 0 0 15px rgba(0, 188, 212, 0.7);
}

/* 颜色选择器样式 */
.control-group input[type="color"] {
  width: 60px;
  height: 40px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  background: transparent;
  box-shadow: 0 0 0 2px rgba(0, 188, 212, 0.2);
}

.control-group input[type="file"] {
  display: none;
}

.file-upload-btn {
  display: inline-block;
  padding: 10px 16px;
  background: linear-gradient(135deg, #00bcd4, #2196f3);
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
  margin-bottom: 8px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  box-shadow: 0 2px 8px rgba(0, 188, 212, 0.3);
}

.file-upload-btn:hover {
  background: linear-gradient(135deg, #00acc1, #1976d2);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 188, 212, 0.4);
}

.file-upload-btn:active {
  transform: translateY(0);
}

.file-upload-wrapper {
  position: relative;
  display: inline-block;
}

.file-name-display {
  display: inline-block;
  margin-left: 10px;
  color: #95e6ff;
  font-size: 12px;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

/* 清除按钮样式 - 科技感红色 */
.clear-btn {
  padding: 6px 12px;
  background: linear-gradient(135deg, #00bcd4, #2196f3);
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  margin-left: 8px;
  transition: all 0.3s ease;
  box-shadow: 0 2px 6px rgba(0, 188, 212, 0.2);
}

.clear-btn:hover {
  background: linear-gradient(135deg, #00acc1, #1976d2);
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(0, 188, 212, 0.3);
}

/* 选择框样式 - 科技感 */
.control-group select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid rgba(0, 188, 212, 0.2);
  border-radius: 6px;
  font-size: 14px;
  background: rgba(255, 255, 255, 0.05);
  color: #e0e0e0;
  cursor: pointer;
  transition: all 0.3s ease;
}

.control-group select:focus {
  outline: none;
  border-color: #00bcd4;
  box-shadow: 0 0 10px rgba(0, 188, 212, 0.3);
}

/* 文本输入框样式 - 科技感 */
.control-group input[type="text"] {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid rgba(0, 188, 212, 0.2);
  border-radius: 6px;
  font-size: 14px;
  background: rgba(255, 255, 255, 0.05);
  color: #e0e0e0;
  transition: all 0.3s ease;
}

.control-group input[type="text"]::placeholder {
  color: rgba(224, 224, 224, 0.5);
}

/* 版权信息 - 缩放卡片样式 */
.copyright-container {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 100;
}

.copyright-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  background: rgba(17, 25, 40, 0.9);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(0, 188, 212, 0.2);
  border-radius: 20px;
  color: #00bcd4;
  font-size: 12px;
  cursor: pointer;
  transition: all 0.3s ease;
  box-shadow: 0 2px 10px rgba(0, 188, 212, 0.1);
}

.copyright-toggle:hover {
  background: rgba(17, 25, 40, 1);
  border-color: #00bcd4;
  box-shadow: 0 4px 15px rgba(0, 188, 212, 0.2);
  transform: translateY(-1px);
}

.toggle-icon {
  font-size: 14px;
  font-weight: bold;
}

.toggle-text {
  transition: opacity 0.3s ease;
}

.copyright-info {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 10px;
  text-align: left;
  background: rgba(17, 25, 40, 0.95);
  backdrop-filter: blur(10px);
  padding: 15px 25px;
  border-radius: 10px;
  border: 1px solid rgba(0, 188, 212, 0.2);
  box-shadow: 0 4px 20px rgba(0, 188, 212, 0.15);
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: all 0.3s ease;
  transform-origin: top left;
  transform: scale(0.8);
  pointer-events: none;
}

.copyright-info.expanded {
  max-height: 300px;
  opacity: 1;
  transform: scale(1);
  pointer-events: auto;
}

.copyright-info p {
  margin: 5px 0;
  color: #95e6ff;
  font-size: 12px;
  letter-spacing: 0.5px;
  font-weight: 500;
}

/* 版权信息中的链接样式 */
.copyright-info a {
  color: #00bcd4;
  text-decoration: none;
  font-weight: 600;
  transition: color 0.3s ease;
}

.copyright-info a:hover {
  color: #2196f3;
  text-shadow: 0 0 10px rgba(0, 188, 212, 0.5);
}

/* 响应式设计 - 科技感 */
@media (max-width: 768px) {
  .app-container {
    flex-direction: column;
  }
  
  .preview-container {
    height: 50vh;
    min-height: 300px;
  }
  
  .controls-panel {
    width: 100%;
    height: 50vh;
    padding: 16px;
    box-shadow: 0 -2px 20px rgba(0, 188, 212, 0.15);
    border-left: none;
    border-top: 1px solid rgba(0, 188, 212, 0.2);
  }
  
  /* 响应式版权信息 */
  .copyright-container {
    position: absolute;
    top: 15px;
    left: 15px;
  }
  
  .copyright-info.expanded {
    max-height: 250px;
  }
  
  .copyright-info p {
    font-size: 11px;
  }
  
  .controls-panel h2 {
    font-size: 18px;
    margin-bottom: 16px;
  }
  
  .control-group {
    margin-bottom: 16px;
  }
  
  .control-group label {
    font-size: 14px;
    margin-bottom: 6px;
  }
  
  .download-btn {
    padding: 12px 16px;
    font-size: 14px;
  }
  
  .clear-btn {
    padding: 4px 10px;
    font-size: 12px;
  }
}

/* 加载状态指示 */
.loading-state {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.loading-spinner {
  width: 50px;
  height: 50px;
  border: 3px solid rgba(0, 188, 212, 0.3);
  border-radius: 50%;
  border-top-color: #00bcd4;
  animation: spin 1s ease-in-out infinite;
  margin-bottom: 15px;
}

.loading-text {
  color: #00bcd4;
  font-size: 14px;
  letter-spacing: 1px;
  text-transform: uppercase;
}

/* 重置按钮样式 - 美化 */
.reset-btn {
  width: 100%;
  padding: 14px 20px;
  background: linear-gradient(135deg, #00bcd4, #2196f3);
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
  margin-top: 16px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  box-shadow: 0 4px 15px rgba(0, 188, 212, 0.3);
}

.reset-btn:hover {
  background: linear-gradient(135deg, #00acc1, #1976d2);
  box-shadow: 0 6px 20px rgba(0, 188, 212, 0.4);
  transform: translateY(-2px);
}

.reset-btn:active {
  transform: translateY(0);
}
</style>